package spring.validation;

import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandles;
import java.nio.charset.Charset;

/**
 * 自定义校验规则
 *
 * @author ME
 * @date 2019年10月23日 下午12:15:56
 */
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = BytesLength.Validator.class)
public @interface BytesLength {
    String message() default "{me.constraints.Size.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    int min() default 0;

    int max() default Integer.MAX_VALUE;

    /**
     * 自定义校验规则
     *
     * @author ME
     * @date 2019年10月23日 下午12:29:14
     */
    class Validator implements ConstraintValidator<BytesLength, String> {

        private static final Log log = LoggerFactory.make(MethodHandles.lookup());

        private int min;
        private int max;

        @Override
        public void initialize(BytesLength constraintAnnotation) {
            min = constraintAnnotation.min();
            max = constraintAnnotation.max();
            validateParameters();
        }

        @Override
        public boolean isValid(String str, ConstraintValidatorContext constraintValidatorContext) {
            if (str == null) {
                return true;
            }
            if (min == max) {
                constraintValidatorContext.disableDefaultConstraintViolation();
                constraintValidatorContext.buildConstraintViolationWithTemplate("长度必须为 " + min)
                    .addConstraintViolation();
            }
            int length = str.getBytes(Charset.forName("GBK")).length;
            return length >= min && length <= max;
        }

        private void validateParameters() {
            if (min < 0) {
                throw log.getMinCannotBeNegativeException();
            }
            if (max < 0) {
                throw log.getMaxCannotBeNegativeException();
            }
            if (max < min) {
                throw log.getLengthCannotBeNegativeException();
            }
        }
    }
}
